<!-- eslint-disable prettier/prettier -->
<template>
  <div class="header">
    <span>底图服务平台</span>
  </div>
  <div id="map"></div>
  <div class="city-btns">
    <div class="city-btn" @click="fitToExtent('tw')">台湾</div>
    <div class="city-btn" @click="fitToExtent('usa')">美国</div>
    <div class="city-btn">加载GEOJSON</div>
    <div class="city-btn" @click="clearGeojson">清空GEOJSON</div>
    <input class="img-input" type="file" @change="uploadFile" />
  </div>
  <div class="edit-forms" v-if="addFileLayer">
    <div class="edit-form">
      <input
        id="refresh-points"
        type="button"
        value="Refresh"
        @click="refreshStyle"
      />
      <h2>Points</h2>
      <div class="edit-form-elem">
        <label for="points-radius">Radius: </label>
        <input type="text" value="2" id="points-radius" />
        <br />
        <label for="points-fill">Fill: </label>
        <input type="text" value="#aa3300" id="points-fill" />
        <br />
        <label for="points-stroke">Stroke: </label>
        <input type="text" value="#ffffff" id="points-stroke" />
      </div>
    </div>

    <div class="edit-form">
      <input
        id="refresh-lines"
        type="button"
        value="Refresh"
        @click="refreshStyle"
      />
      <h2>Lines</h2>
      <div class="edit-form-elem">
        <label for="line-wdith">Line Width: </label>
        <input type="text" value="2" id="line-wdith" />
        <br />
        <label for="line-color">Line Color: </label>
        <input type="text" value="#aa3300" id="line-color" />
      </div>
    </div>

    <div class="edit-form">
      <input
        id="refresh-polygons"
        type="button"
        value="Refresh"
        @click="refreshStyle"
      />
      <h2>Polygons</h2>
      <div class="edit-form-elem">
        <label for="polygon-width">Outline Width: </label>
        <input type="text" value="2" id="polygon-width" />
        <br />
        <label for="polygon-color">Line Color: </label>
        <input type="text" value="blue" id="polygon-color" />
        <br />
        <label for="polygon-fill">Fill: </label>
        <input type="text" value="blue" id="polygon-fill" />
      </div>
    </div>
  </div>
</template>

<script setup>
import "ol/ol.css";
import { Map, View } from "ol";
import TileLayer from "ol/layer/Tile";
import { XYZ } from "ol/source";
import TileGrid from "ol/tilegrid/TileGrid";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import { GeoJSON } from "ol/format";

import axios from "axios";
import { Circle as CircleStyle, Fill, Stroke, Style } from "ol/style";

import { ref, onMounted } from "vue";

let map;
let addFileLayer = ref(null);
const initMap = () => {
  map = new Map({
    target: "map",
    layers: [],
    view: new View({
      projection: "EPSG:4326",
      center: [121.509064, 23.044333],
      zoom: 8,
    }),
  });
};

function elementToJSON(element) {
  const obj = {};

  if (element.nodeType === 3) {
    obj["#text"] = element.nodeValue;
  } else {
    if (element.hasChildNodes()) {
      for (let i = 0; i < element.childNodes.length; i++) {
        const child = element.childNodes[i];
        const nodeName = child.nodeName;
        if (obj[nodeName] === undefined) {
          obj[nodeName] = elementToJSON(child);
        } else {
          if (!Array.isArray(obj[nodeName])) {
            obj[nodeName] = [obj[nodeName]];
          }
          obj[nodeName].push(elementToJSON(child));
        }
      }
    }
  }
  return obj;
}

// ol.source.XYZ添加瓦片地图的层
function zeroFill(num, len, radix) {
  var str = num.toString(radix || 10);
  while (str.length < len) {
    str = "0" + str;
  }
  return str;
}

const removeLayer = (layer) => {
  if (layer) {
    map.removeLayer(layer);
  }
};

const removeLayerId = (id) => {
  const allArray = map.getLayers().getArray();
  const layers = allArray.filter((layer) => {
    if (layer.get("id")) {
      return layer.get("id") === id;
    }
    return false;
  });

  if (Array.isArray(layers)) {
    layers.forEach((layer) => removeLayer(layer));
  }
};

const styleFunction = (feature) => {
  const type = feature.getGeometry().getType();
  if (type === "Point") {
    return new Style({
      image: new CircleStyle({
        radius: document.getElementById("points-radius").value,
        fill: new Fill({
          color: document.getElementById("points-fill").value,
        }),
        stroke: new Stroke({
          color: document.getElementById("points-stroke").value,
          width: 1,
        }),
      }),
    });
  } else if (type === "Polygon") {
    return new Style({
      stroke: new Stroke({
        color: document.getElementById("polygon-color").value,
        width: document.getElementById("polygon-width").value,
      }),
      fill: new Fill({
        color: document.getElementById("polygon-fill").value,
      }),
    });
  } else if (type === "LineString") {
    return new Style({
      stroke: new Stroke({
        color: document.getElementById("line-color").value,
        width: document.getElementById("line-width").value,
      }),
    });
  }
};

const uploadFile = function (e) {
  const file = e.target.files[0];

  const reader = new FileReader();

  reader.onload = function (e) {
    const contents = e.target.result;
    const json = JSON.parse(contents);
    // 可在此处处理读取到的JSON数据
    removeLayerId("local-file");
    const vectorSource = new VectorSource();
    const vectorLayer = new VectorLayer({
      id: "local-file",
      source: vectorSource,
      style: styleFunction,
    });
    addFileLayer.value = vectorLayer;
    if (json.geometries) {
      const features = json.geometries.map((geometry) => {
        const feature = new GeoJSON().readFeature(geometry);
        feature.setStyle(styleFunction);
        return feature;
      });
      vectorSource.addFeatures(features);
    }
    map.addLayer(vectorLayer);
  };

  reader.readAsText(file);
};

const clearGeojson = () => {
  if (addFileLayer.value) {
    removeLayerId("local-file");
    addFileLayer.value = undefined;
  }
};

const addImgLayer = () => {
  axios
    .get("./_alllayers/conf.xml")
    .then((response) => {
      const parser = new DOMParser();
      const xmlDoc = parser.parseFromString(response.data, "text/xml");
      const jsonObj = elementToJSON(xmlDoc);

      const array =
        jsonObj["CacheInfo"]["TileCacheInfo"]["LODInfos"]["LODInfo"];
      const resolutions = array.map((it) => it["Resolution"]["#text"]["#text"]);

      const firstRes = resolutions[0];
      const newResolutions = [firstRes];
      for (let i = 1; i < 16; i++) {
        const res = Number(firstRes) / Math.pow(2, i);
        newResolutions.push(`${res}`);
      }
      console.info(resolutions, newResolutions);

      const originX = Number(
        jsonObj.CacheInfo.TileCacheInfo.TileOrigin.X["#text"]["#text"]
      );
      const originY = Number(
        jsonObj.CacheInfo.TileCacheInfo.TileOrigin.Y["#text"]["#text"]
      );
      const tileSize = Number(
        jsonObj.CacheInfo.TileCacheInfo.TileRows["#text"]["#text"]
      );
      const customTileGrid = new TileGrid({
        origin: [originX, originY], // 对应TileOrigin
        tileSize,
        resolutions: newResolutions, // 分辨率数组
      });

      const tileLayer = new TileLayer({
        source: new XYZ({
          projection: "EPSG:4326",
          tileGrid: customTileGrid,
          tileUrlFunction: function (tileCoord) {
            //alert(coordinate[0] + " X= " + coordinate[1] + " Y= " + coordinate[2]);
            const oo = "00000000";

            const z = "L" + zeroFill(tileCoord[0], 2, 10);
            const xx = tileCoord[1].toString(16);
            const x = "C" + oo.substring(0, 8 - xx.length) + xx;
            const yy = tileCoord[2].toString(16).toLowerCase(); //减1
            const y = "R" + oo.substring(0, 8 - yy.length) + yy;

            const tilePath = "./_alllayers/" + z + "/" + y + "/" + x + ".png";
            return tilePath;
          },
        }),
      });

      map.addLayer(tileLayer); //添加到map里面
    })
    .catch((error) => {
      console.error(error);
    });
};

const extents = {
  usa: [
    229.89798001562505, 23.343750000000014, 299.647980015625, 51.60937500000001,
  ],
  tw: [119.803, 21.741, 122.549, 25.775],
};
const fitToExtent = (type) => {
  map.getView().fit(extents[type]);
};

const refreshStyle = () => {
  if (addFileLayer.value) {
    addFileLayer.value.getSource()?.forEachFeature((f) => {
      f.setStyle(styleFunction);
    });
  }
};

onMounted(() => {
  //调用加载
  initMap();
  addImgLayer();
  // addShpBoundary();
});
</script>
<style lang="less">
.header {
  width: 100%;
  height: 50px;
  background: #000;
  color: #fff;
  padding: 0 24px;
  text-align: left;
  > span {
    font-size: 20px;
    line-height: 50px;
  }
}

#map {
  flex: 1;
}

.city-btns {
  position: absolute;
  top: 60px;
  left: 60px;
  z-index: 999;
  display: flex;
  gap: 20px;
}

.city-btns > .city-btn {
  background: #ddd;
  padding: 10px 20px;
  font-size: 14px;
  font-weight: bold;
  cursor: pointer;
  border-radius: 10px;
}

.city-btn:hover {
  background: #ccc;
}

.img-input {
  width: 136px;
  height: 40px;
  position: absolute;
  top: 0;
  left: 177px;
  opacity: 0;
  cursor: pointer;
}

.edit-forms {
  position: absolute;
  bottom: 10px;
  right: 20px;
  display: flex;
  padding: 10px;
  border: 1px solid #000;

  .edit-form {
    display: inline-block;
    margin: 5px;
    padding: 10px;
    border: 1px solid black;
    white-space: nowrap;
  }

  .edit-form h2 {
    font-size: 1.5em;
  }

  .edit-form input[type="button"] {
    float: right;
  }

  .edit-form-elem label {
    display: inline-block;
    width: 85px;
  }

  .edit-form-elem input[type="text"],
  .edit-form-elem select {
    width: 130px;
  }
}
</style>
